/***************************************************************************
 *   oboe.core.Controller                                                  *
 *   Copyright (C) 2011 by Felipe Manga                                    *
 *   lufeboma@gmail.com                                                    *
 *                                                                         *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the       *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to    *
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:                                             *
 *                                                                         *
 *   The above copyright notice and this permission notice shall be        *
 *   included in all copies or substantial portions of the Software.       *
 *                                                                         *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
 ***************************************************************************/

package oboe.core
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	
	import oboe.utils.CallbackHandle;
	import oboe.utils.Prototype;

	public class Controller extends SigSlot
	{
		
		private var displayObject:DisplayObject;
		private var callbacks:Vector.<CallbackHandle>;
		
		public function Controller( displayObject:DisplayObject=null )
		{
			if( !displayObject )
			{
				displayObject = new Sprite();
			}
			this.displayObject = displayObject;
			Oboe.controllerLookup[ displayObject ] = this;
		}
		
		protected function addAssetCallback( name:String, func:Function, ... arguments ):CallbackHandle
		{
			var cb:CallbackHandle;
			if( !this.callbacks ) this.callbacks = new Vector.<CallbackHandle>();
			arguments.unshift( func );
			arguments.unshift( name );
			arguments.unshift( this.displayObject );
			cb = Prototype.addCallback.apply( null, arguments );
			this.callbacks.push( cb );
			return cb;
		}

		protected function addAssetCallbackEx( name:String, func:Function, ... arguments ):CallbackHandle
		{
			var cb:CallbackHandle;
			if( !this.callbacks ) this.callbacks = new Vector.<CallbackHandle>();
			arguments.unshift( func );
			arguments.unshift( name );
			arguments.unshift( this.displayObject );
			cb = Prototype.addCallbackEx.apply( null, arguments );
			this.callbacks.push( cb );
			return cb;
		}
		
		protected function removeAssetCallback( key:CallbackHandle ):void
		{
			var i:int = callbacks.indexOf( key );
			if( i==-1 ) return;
			// Object(this.displayObject).removeCallback( key );
			Prototype.removeCallback( this.displayObject, key );
			this.callbacks[i] = this.callbacks[ this.callbacks.length-1 ];
			this.callbacks.pop();
		}
		
		protected function releaseDisplayObject():void
		{
			this.displayObject = null;
		}
		
		protected function setDisplayObject( ndo:DisplayObject, preserveCallbacks:Boolean=false ):void
		{
			if( this.displayObject == ndo ) return;
			
			var parent:DisplayObjectContainer;
			if( this.displayObject )
			{
				delete Oboe.controllerLookup[ this.displayObject ];
				if( this.displayObject.parent )
				{
					parent = this.displayObject.parent;
					var z:int = parent.getChildIndex(this.displayObject);
					parent.addChildAt( ndo, z );
					parent.removeChild( this.displayObject );
				}
			}
			else
			{
				var parentSigSlot:SigSlot = this.getSigSlotParent();
				if( parentSigSlot && parentSigSlot is Controller && Controller(parentSigSlot).displayObject is DisplayObjectContainer )
				{
					parent = DisplayObjectContainer( Controller(parentSigSlot).displayObject );
					if( parent )
					{
						parent.addChild( ndo );
					}
				}
			}
			this.displayObject = ndo;
			Oboe.controllerLookup[ ndo ] = this;
			
			if( preserveCallbacks )
			{
				for each( var c:Object in this.callbacks )
				{
					this.displayObject.addEventListener( c.event, c.cb );
				}
			}
			else
			{
				this.callbacks = null;
			}
		}
		
		protected override function removeChild(child:SigSlotCollection):void
		{
			super.removeChild( child );
			if( child is Controller )
			{
				var c:Controller = Controller(child);
				if( c.displayObject && c.displayObject.parent == this.displayObject )
				{
					DisplayObjectContainer(this.displayObject).removeChild( c.displayObject );
				}
			}
		}
		
		protected override function addChild(child:SigSlotCollection):void
		{
			if( child is Controller )
			{
				DisplayObjectContainer(this.displayObject).addChild( Controller(child).displayObject ); 
			}
			super.addChild( child );
		}
		
		protected function getDisplayObject():DisplayObject
		{
			return this.displayObject;
		}
		
		public function slot__getDisplayObject( ret:Array ):void
		{
			ret.push( this.displayObject );
		}
	}
}